<!DOCTYPE html>
<html lang="en">
  <head>
    <title>
        Java-Se-网络编程-1 - rulerLwx Blog
      </title>
        <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    
    <meta name="theme-color" content="#000000" />
    
    <meta http-equiv="window-target" content="_top" />
    
    
    <meta name="description" content="网络分层 GET/POST 类与API InetAddress 将IP地址封装成一个类， URLDecoder、URLEncoder 普通字符串与application/x-www-fo" />
    <meta name="generator" content="Hugo 0.73.0 with theme pure" />
    <title>Java-Se-网络编程-1 - rulerLwx Blog</title>
    
    
    <link rel="stylesheet" href="https://rulerLwx.gitee.io/css/style.min.c4bc7071f132c964c2116bca53b392933f377e5ca7b7051ed245187c621a2d3e.css">
    
    <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/9.15.10/styles/github.min.css" async>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css" async>
    <meta property="og:title" content="Java-Se-网络编程-1" />
<meta property="og:description" content="网络分层 GET/POST 类与API InetAddress 将IP地址封装成一个类， URLDecoder、URLEncoder 普通字符串与application/x-www-fo" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://rulerLwx.gitee.io/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-1/" />
<meta property="article:published_time" content="2017-07-01T11:13:47+08:00" />
<meta property="article:modified_time" content="2017-07-01T11:13:47+08:00" />
<meta itemprop="name" content="Java-Se-网络编程-1">
<meta itemprop="description" content="网络分层 GET/POST 类与API InetAddress 将IP地址封装成一个类， URLDecoder、URLEncoder 普通字符串与application/x-www-fo">
<meta itemprop="datePublished" content="2017-07-01T11:13:47&#43;08:00" />
<meta itemprop="dateModified" content="2017-07-01T11:13:47&#43;08:00" />
<meta itemprop="wordCount" content="7864">



<meta itemprop="keywords" content="网络编程," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Java-Se-网络编程-1"/>
<meta name="twitter:description" content="网络分层 GET/POST 类与API InetAddress 将IP地址封装成一个类， URLDecoder、URLEncoder 普通字符串与application/x-www-fo"/>

    <!--[if lte IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
      <![endif]-->

    <!--[if lt IE 9]>
        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
      <![endif]-->
  </head>

  
  

  <body class="main-center theme-black" itemscope itemtype="http://schema.org/WebPage"><header class="header" itemscope itemtype="http://schema.org/WPHeader">
    <div class="slimContent">
      <div class="navbar-header">
        <div class="profile-block text-center">
          <a id="avatar" href="https://gitee.com/rulerLwx" target="_blank">
            <img class="img-circle img-rotate" src="https://rulerLwx.gitee.io/avatar.png" width="200" height="200">
          </a>
          <h2 id="name" class="hidden-xs hidden-sm">rulerLwx</h2>
          <h3 id="title" class="hidden-xs hidden-sm hidden-md">thinking...</h3>
          <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i>Guangzhou, China</small>
        </div><div class="search" id="search-form-wrap">
    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="Search" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i
                        class="icon icon-search"></i></button>
            </span>
        </div>
        <div class="ins-search">
            <div class="ins-search-mask"></div>
            <div class="ins-search-container">
                <div class="ins-input-wrapper">
                    <input type="text" class="ins-search-input" placeholder="Type something..."
                        x-webkit-speech />
                    <button type="button" class="close ins-close ins-selectable" data-dismiss="modal"
                        aria-label="Close"><span aria-hidden="true">×</span></button>
                </div>
                <div class="ins-section-wrapper">
                    <div class="ins-section-container"></div>
                </div>
            </div>
        </div>
    </form>
</div>
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
        <ul class="nav navbar-nav main-nav">
            <li class="menu-item menu-item-home">
                <a href="/">
                    <i class="icon icon-home-fill"></i>
                  <span class="menu-title">Home</span>
                </a>
            </li>
            <li class="menu-item menu-item-archives">
                <a href="/posts/">
                    <i class="icon icon-archives-fill"></i>
                  <span class="menu-title">Archives</span>
                </a>
            </li>
            <li class="menu-item menu-item-categories">
                <a href="/categories/">
                    <i class="icon icon-folder"></i>
                  <span class="menu-title">Categories</span>
                </a>
            </li>
            <li class="menu-item menu-item-tags">
                <a href="/tags/">
                    <i class="icon icon-tags"></i>
                  <span class="menu-title">Tags</span>
                </a>
            </li>
            <li class="menu-item menu-item-about">
                <a href="/about/">
                    <i class="icon icon-cup-fill"></i>
                  <span class="menu-title">About</span>
                </a>
            </li>
        </ul>
      </nav>
    </div>
  </header>

<aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">Board</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">enjoy~
            </div>
        </div>
    </div>
</div>

      <div class="widget">
    <h3 class="widget-title"> Categories</h3>
    <div class="widget-body">
        <ul class="category-list">
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-framework/" class="category-list-link">java-framework</a><span class="category-list-count">38</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-front-end/" class="category-list-link">java-front-end</a><span class="category-list-count">11</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-se/" class="category-list-link">java-se</a><span class="category-list-count">21</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-senior/" class="category-list-link">java-senior</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/linux/" class="category-list-link">linux</a><span class="category-list-count">13</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/tools/" class="category-list-link">tools</a><span class="category-list-count">1</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E7%83%A9/" class="category-list-link">技术杂烩</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-list-link">数据库</a><span class="category-list-count">15</span></li>
        </ul>
    </div>
</div>
      <div class="widget">
    <h3 class="widget-title"> Tags</h3>
    <div class="widget-body">
        <ul class="tag-list">
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/jvm/" class="tag-list-link">jvm</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" class="tag-list-link">多线程</a><span
                    class="tag-list-count">2</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" class="tag-list-link">网络编程</a><span
                    class="tag-list-count">3</span></li>
            
        </ul>

    </div>
</div>
      
<div class="widget">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget-body">
        <ul class="recent-post-list list-unstyled no-thumbnail">
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E4%B8%80%E6%89%B9%E9%87%8F%E7%A7%BB%E5%8A%A8%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6/" class="title">自己动手（一）——批量移动、重命名文件</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-27 17:50:02 &#43;0800 CST" itemprop="datePublished">2020-07-27</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E5%85%B3%E4%BA%8Einteger%E7%9A%84-128~127%E7%BC%93%E5%AD%98/" class="title">关于Integer的 -128~127缓存</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-11 16:56:21 &#43;0800 CST" itemprop="datePublished">2020-07-11</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98/" class="title">跨域问题</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-08 22:41:12 &#43;0800 CST" itemprop="datePublished">2020-07-08</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/" class="title">个人博客搭建</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-05 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-05</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/mongodb-1/" class="title">MonggoDB-1</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-03 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-03</time>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</div>
  </div>
</aside>

    
    
<aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <h4 class="toc-title">Catalogue</h4>
    <nav id="toc" class="js-toc toc">

    </nav>
  </div>
</aside>
<main class="main" role="main"><div class="content">
  <article id="-" class="article article-type-" itemscope
    itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      <h1 itemprop="name">
  <a
    class="article-title"
    href="/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-1/"
    >Java-Se-网络编程-1</a
  >
</h1>

      <div class="article-meta">
        
<span class="article-date">
  <i class="icon icon-calendar-check"></i>&nbsp;
<a href="https://rulerLwx.gitee.io/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-1/" class="article-date">
  <time datetime="2017-07-01 11:13:47 &#43;0800 CST" itemprop="datePublished">2017-07-01</time>
</a>
</span>
<span class="article-category">
  <i class="icon icon-folder"></i>&nbsp;
  <a class="article-category-link" href="/categories/java-se/"> Java-Se </a>
</span>  
  <span class="article-tag">
    <i class="icon icon-tags"></i>&nbsp;
    <a class="article-tag-link" href="/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"> 网络编程 </a>
  </span>

        <span class="post-comment"><i class="icon icon-comment"></i>&nbsp;<a href="/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-1/#comments"
            class="article-comment-link">Comments</a></span>
		<span class="post-wordcount hidden-xs" itemprop="wordCount">Word Count: 7864words</span>
		<span class="post-readcount hidden-xs" itemprop="timeRequired">Read Count: 16minutes </span>
      </div>
    </div>
    <div class="article-entry marked-body js-toc-content" itemprop="articleBody">
      <h1 id="网络分层">网络分层</h1>
<p><img src="https://oscimg.oschina.net/oscnet/94f7613301801bab487d0342afe2f1ac07a.jpg" alt="osi-tcp-ip" title="osi-tcp-ip"></p>
<p><img src="https://oscimg.oschina.net/oscnet/ab08b17d8d50d151a1adc405cfdce62b6ac.jpg" alt="tcp-ip" title="tcp-ip"></p>
<h1 id="getpost">GET/POST</h1>
<h2 id="类与api">类与API</h2>
<h3 id="inetaddress">InetAddress</h3>
<p>将IP地址封装成一个类，</p>
<h3 id="urldecoderurlencoder">URLDecoder、URLEncoder</h3>
<p>普通字符串与application/x-www-form-urlencoded MIME转换</p>
<h3 id="urlurlconnectionurlpermission">URL、URLConnection、URLPermission</h3>
<p>URI是一种抽象，URL是URI的一种具体实现。URL是一种绝对定位，必须能找到资源。
通过URL能获取URLConnection，URLPermission是JDK8提供的用于管理URLConnection权限问题。</p>
<h1 id="getpost示例">GET/POST示例</h1>
<pre><code class="language-java">import java.io.*;
import java.net.*;
import java.util.*;

public class GetPostTest
{
    /**
    * 向指定URL发送GET方法的请求
    * @param url 发送请求的URL
    * @param param 请求参数，格式满足name1=value1&amp;name2=value2的形式。
    * @return URL所代表远程资源的响应
    */
    public static String sendGet(String url , String param)
    {
        String result = &quot;&quot;;
        String urlName = url + &quot;?&quot; + param;
        try
        {
            URL realUrl = new URL(urlName);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty(&quot;accept&quot;, &quot;*/*&quot;);
            conn.setRequestProperty(&quot;connection&quot;, &quot;Keep-Alive&quot;);
            conn.setRequestProperty(&quot;user-agent&quot;
                , &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)&quot;);
            // 建立实际的连接
            conn.connect();
            // 获取所有响应头字段
            Map&lt;String, List&lt;String&gt;&gt; map = conn.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet())
            {
                System.out.println(key + &quot;---&gt;&quot; + map.get(key));
            }
            try(
                // 定义BufferedReader输入流来读取URL的响应
                BufferedReader in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream() , &quot;utf-8&quot;)))
            {
                String line;
                while ((line = in.readLine())!= null)
                {
                    result += &quot;\n&quot; + line;
                }
            }
        }
        catch(Exception e)
        {
            System.out.println(&quot;发送GET请求出现异常！&quot; + e);
            e.printStackTrace();
        }
        return result;
    }
    /**
    * 向指定URL发送POST方法的请求
    * @param url 发送请求的URL
    * @param param 请求参数，格式应该满足name1=value1&amp;name2=value2的形式。
    * @return URL所代表远程资源的响应
    */
    public static String sendPost(String url , String param)
    {
        String result = &quot;&quot;;
        try
        {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty(&quot;accept&quot;, &quot;*/*&quot;);
            conn.setRequestProperty(&quot;connection&quot;, &quot;Keep-Alive&quot;);
            conn.setRequestProperty(&quot;user-agent&quot;,
            &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)&quot;);
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            try(
                // 获取URLConnection对象对应的输出流
                PrintWriter out = new PrintWriter(conn.getOutputStream()))
            {
                // 发送请求参数
                out.print(param);
                // flush输出流的缓冲
                out.flush();
            }
            try(
                // 定义BufferedReader输入流来读取URL的响应
                BufferedReader in = new BufferedReader(new InputStreamReader
                    (conn.getInputStream() , &quot;utf-8&quot;)))
            {
                String line;
                while ((line = in.readLine())!= null)
                {
                    result += &quot;\n&quot; + line;
                }
            }
        }
        catch(Exception e)
        {
            System.out.println(&quot;发送POST请求出现异常！&quot; + e);
            e.printStackTrace();
        }
        return result;
    }
    // 提供主方法，测试发送GET请求和POST请求
    public static void main(String args[])
    {
        // 发送GET请求
        String s = GetPostTest.sendGet(&quot;http://localhost:8888/abc/a.jsp&quot;
            , null);
        System.out.println(s);
        // 发送POST请求
        String s1 = GetPostTest.sendPost(&quot;http://localhost:8888/abc/login.jsp&quot;
            , &quot;name=crazyit.org&amp;pass=leegang&quot;);
        System.out.println(s1);
    }
}
</code></pre>
<h1 id="tcp">TCP</h1>
<p>tcp/ip，两端各建立一个Socket，并通过Socket产生IO流来进行网络通信。</p>
<p>tcp是一种可靠的网络协议（三次握手）。</p>
<p>TCP分客户端、服务端，分别用Socket、ServiceSocket表示。Socket也称“套接字”。</p>
<h2 id="示例">示例</h2>
<p>Server.java</p>
<pre><code class="language-java">
import java.net.*;
import java.io.*;

public class Server
{
    public static void main(String[] args) throws IOException
    {
        // 创建一个ServerSocket，用于监听客户端Socket的连接请求
        ServerSocket ss = new ServerSocket(30000);
        // 采用循环不断接受来自客户端的请求
        while (true)
        {
            // 每当接受到客户端Socket的请求，服务器端也对应产生一个Socket
            Socket s = ss.accept();
            // 将Socket对应的输出流包装成PrintStream
            PrintStream ps = new PrintStream(s.getOutputStream());
            // 进行普通IO操作
            ps.println(&quot;您好，您收到了服务器的新年祝福！&quot;);
            // 关闭输出流，关闭Socket
            ps.close();
            s.close();
        }
    }
}
</code></pre>
<p>Client.java</p>
<pre><code class="language-java">
import java.net.*;
import java.io.*;

public class Client
{
    public static void main(String[] args)
        throws IOException
    {
        Socket socket = new Socket(&quot;127.0.0.1&quot; , 30000);   // ①
        // 将Socket对应的输入流包装成BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        // 进行普通IO操作
        String line = br.readLine();
        System.out.println(&quot;来自服务器的数据：&quot; + line);
        // 关闭输入流、socket
        br.close();
        socket.close();
    }
}
</code></pre>
<h2 id="加入多线程的tcp通信">加入多线程的TCP通信</h2>
<p>服务端为接收到的每一个客户端开启一个线程进行相应数据处理。</p>
<h3 id="示例-1">示例</h3>
<p>MyServer.java</p>
<pre><code class="language-java">
import java.net.*;
import java.io.*;
import java.util.*;

public class MyServer
{
    // 定义保存所有Socket的ArrayList，并将其包装为线程安全的
    public static List&lt;Socket&gt; socketList
        = Collections.synchronizedList(new ArrayList&lt;&gt;());
    public static void main(String[] args)
        throws IOException
    {
        ServerSocket ss = new ServerSocket(30000);
        while(true)
        {
            // 此行代码会阻塞，将一直等待别人的连接
            Socket s = ss.accept();
            socketList.add(s);
            // 每当客户端连接后启动一条ServerThread线程为该客户端服务
            new Thread(new ServerThread(s)).start();
        }
    }
}
</code></pre>
<p>ServerThread.java</p>
<pre><code class="language-java">
import java.io.*;
import java.net.*;

// 负责处理每个线程通信的线程类
public class ServerThread implements Runnable
{
    // 定义当前线程所处理的Socket
    Socket s = null;
    // 该线程所处理的Socket所对应的输入流
    BufferedReader br = null;
    public ServerThread(Socket s)
    throws IOException
    {
        this.s = s;
        // 初始化该Socket对应的输入流
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    }
    public void run()
    {
        try
        {
            String content = null;
            // 采用循环不断从Socket中读取客户端发送过来的数据
            while ((content = readFromClient()) != null)
            {
                // 遍历socketList中的每个Socket，
                // 将读到的内容向每个Socket发送一次
                for (Socket s : MyServer.socketList)
                {
                    PrintStream ps = new PrintStream(s.getOutputStream());
                    ps.println(content);
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    // 定义读取客户端数据的方法
    private String readFromClient()
    {
        try
        {
            return br.readLine();
        }
        // 如果捕捉到异常，表明该Socket对应的客户端已经关闭
        catch (IOException e)
        {
            // 删除该Socket。
            MyServer.socketList.remove(s);      // ①
        }
        return null;
    }
}
</code></pre>
<p>MyClient.java</p>
<pre><code class="language-java">
import java.io.*;
import java.net.*;

public class MyClient
{
    public static void main(String[] args)throws Exception
    {
        Socket s = new Socket(&quot;127.0.0.1&quot; , 30000);
        // 客户端启动ClientThread线程不断读取来自服务器的数据
        new Thread(new ClientThread(s)).start();   // ①
        // 获取该Socket对应的输出流
        PrintStream ps = new PrintStream(s.getOutputStream());
        String line = null;
        // 不断读取键盘输入
        BufferedReader br = new BufferedReader(
            new InputStreamReader(System.in));
        while ((line = br.readLine()) != null)
        {
            // 将用户的键盘输入内容写入Socket对应的输出流
            ps.println(line);
        }
    }
}
</code></pre>
<p>ClientThread.java</p>
<pre><code class="language-java">
import java.io.*;
import java.net.*;

public class ClientThread implements Runnable
{
    // 该线程负责处理的Socket
    private Socket s;
    // 该线程所处理的Socket所对应的输入流
    BufferedReader br = null;
    public ClientThread(Socket s)
        throws IOException
    {
        this.s = s;
        br = new BufferedReader(
            new InputStreamReader(s.getInputStream()));
    }
    public void run()
    {
        try
        {
            String content = null;
            // 不断读取Socket输入流中的内容，并将这些内容打印输出
            while ((content = br.readLine()) != null)
            {
                System.out.println(content);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
</code></pre>
<h1 id="半关闭socket">半关闭Socket</h1>
<ul>
<li>shutdownInput()：关闭该Socket的输入流，程序还可通过该Socket的输出流输出数据。</li>
<li>hutdownOutput()：关闭该Socket的输出流，程序还可通过该Socket的输入流读取数据。</li>
</ul>
<p>“半关闭”，指关闭了输出流或输入流，但Socket还没有完全关闭。
半关闭的目的：表示输入或输出流已经传输结束。
如果一个Socket先后调用了shutdownInput()、shutdownOutput()方法，该Socket实例依然没有被关闭，只是该Socket既不能输出数据，也不能读取数据而已。</p>
<p>当调用shutdownInput()或shutdownOutput()方法关闭了输入或输出流之后，该Socket无法再次打开输入或输出流。因此这种做法通常不适合保持持久通信状态的交互式应用，只适用于一站式的通信协议，例如HTTP协议——客户端连接到服务器后，开始发送请求数据，发送完成后无须再次发送数据，只需读取服务端响应数据即可，当读取完成后，该Socket连接也被关闭了。</p>
<h1 id="使用bio实现阻塞通信">使用BIO实现阻塞通信</h1>
<p>BIO（block input output），这是传统的IO操作。</p>
<h1 id="使用nio实现非阻塞通信">使用NIO实现非阻塞通信</h1>
<p>NIO（New IO）是JDK1.4开始提供的API。</p>
<p>主要是使用Selector类，用于监控SelectableChannel的IO状况。只有当IO操作准备好时（通道注册时设置不同的状态，如SelectionKey.OP_READ）才会把IO交给线程处理。</p>
<p>所有的Channel默认都是阻塞模式。</p>
<h2 id="示例-2">示例</h2>
<p>NServer.java</p>
<pre><code class="language-java">
import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class NServer
{
    // 用于检测所有Channel状态的Selector
    private Selector selector = null;
    static final int PORT = 30000;
    // 定义实现编码、解码的字符集对象
    private Charset charset = Charset.forName(&quot;UTF-8&quot;);
    public void init()throws IOException
    {
        selector = Selector.open();
        // 通过open方法来打开一个未绑定的ServerSocketChannel实例
        ServerSocketChannel server = ServerSocketChannel.open();
        InetSocketAddress isa = new InetSocketAddress(&quot;127.0.0.1&quot;, PORT);
        // 将该ServerSocketChannel绑定到指定IP地址
        server.bind(isa);
        // 设置ServerSocket以非阻塞方式工作
        server.configureBlocking(false);
        // 将server注册到指定Selector对象
        server.register(selector, SelectionKey.OP_ACCEPT);
        while (selector.select() &gt; 0)
        {
            // 依次处理selector上的每个已选择的SelectionKey
            for (SelectionKey sk : selector.selectedKeys())
            {
                // 从selector上的已选择Key集中删除正在处理的SelectionKey
                selector.selectedKeys().remove(sk);      // ①
                // 如果sk对应的Channel包含客户端的连接请求
                if (sk.isAcceptable())        // ②
                {
                    // 调用accept方法接受连接，产生服务器端的SocketChannel
                    SocketChannel sc = server.accept();
                    // 设置采用非阻塞模式
                    sc.configureBlocking(false);
                    // 将该SocketChannel也注册到selector
                    sc.register(selector, SelectionKey.OP_READ);
                    // 将sk对应的Channel设置成准备接受其他请求
                    sk.interestOps(SelectionKey.OP_ACCEPT);
                }
                // 如果sk对应的Channel有数据需要读取
                if (sk.isReadable())     // ③
                {
                    // 获取该SelectionKey对应的Channel，该Channel中有可读的数据
                    SocketChannel sc = (SocketChannel)sk.channel();
                    // 定义准备执行读取数据的ByteBuffer
                    ByteBuffer buff = ByteBuffer.allocate(1024);
                    String content = &quot;&quot;;
                    // 开始读取数据
                    try
                    {
                        while(sc.read(buff) &gt; 0)
                        {
                            buff.flip();
                            content += charset.decode(buff);
                        }
                        // 打印从该sk对应的Channel里读取到的数据
                        System.out.println(&quot;读取的数据：&quot; + content);
                        // 将sk对应的Channel设置成准备下一次读取
                        sk.interestOps(SelectionKey.OP_READ);
                    }
                    // 如果捕捉到该sk对应的Channel出现了异常，即表明该Channel
                    // 对应的Client出现了问题，所以从Selector中取消sk的注册
                    catch (IOException ex)
                    {
                        // 从Selector中删除指定的SelectionKey
                        sk.cancel();
                        if (sk.channel() != null)
                        {
                            sk.channel().close();
                        }
                    }
                    // 如果content的长度大于0，即聊天信息不为空
                    if (content.length() &gt; 0)
                    {
                        // 遍历该selector里注册的所有SelectionKey
                        for (SelectionKey key : selector.keys())
                        {
                            // 获取该key对应的Channel
                            Channel targetChannel = key.channel();
                            // 如果该channel是SocketChannel对象
                            if (targetChannel instanceof SocketChannel)
                            {
                                // 将读到的内容写入该Channel中
                                SocketChannel dest = (SocketChannel)targetChannel;
                                dest.write(charset.encode(content));
                            }
                        }
                    }
                }
            }
        }
    }
    public static void main(String[] args)
        throws IOException
    {
        new NServer().init();
    }
}
</code></pre>
<p>NClient.java</p>
<pre><code class="language-java">
import java.util.*;
import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class NClient
{
    // 定义检测SocketChannel的Selector对象
    private Selector selector = null;
    static final int PORT = 30000;
    // 定义处理编码和解码的字符集
    private Charset charset = Charset.forName(&quot;UTF-8&quot;);
    // 客户端SocketChannel
    private SocketChannel sc = null;
    public void init()throws IOException
    {
        selector = Selector.open();
        InetSocketAddress isa = new InetSocketAddress(&quot;127.0.0.1&quot;, PORT);
        // 调用open静态方法创建连接到指定主机的SocketChannel
        sc = SocketChannel.open(isa);
        // 设置该sc以非阻塞方式工作
        sc.configureBlocking(false);
        // 将SocketChannel对象注册到指定Selector
        sc.register(selector, SelectionKey.OP_READ);
        // 启动读取服务器端数据的线程
        new ClientThread().start();
        // 创建键盘输入流
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextLine())
        {
            // 读取键盘输入
            String line = scan.nextLine();
            // 将键盘输入的内容输出到SocketChannel中
            sc.write(charset.encode(line));
        }
    }
    // 定义读取服务器数据的线程
    private class ClientThread extends Thread
    {
        public void run()
        {
            try
            {
                while (selector.select() &gt; 0)    // ①
                {
                    // 遍历每个有可用IO操作Channel对应的SelectionKey
                    for (SelectionKey sk : selector.selectedKeys())
                    {
                        // 删除正在处理的SelectionKey
                        selector.selectedKeys().remove(sk);
                        // 如果该SelectionKey对应的Channel中有可读的数据
                        if (sk.isReadable())
                        {
                            // 使用NIO读取Channel中的数据
                            SocketChannel sc = (SocketChannel)sk.channel();
                            ByteBuffer buff = ByteBuffer.allocate(1024);
                            String content = &quot;&quot;;
                            while(sc.read(buff) &gt; 0)
                            {
                                sc.read(buff);
                                buff.flip();
                                content += charset.decode(buff);
                            }
                            // 打印输出读取的内容
                            System.out.println(&quot;聊天信息：&quot; + content);
                            // 为下一次读取作准备
                            sk.interestOps(SelectionKey.OP_READ);
                        }
                    }
                }
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
    }
    public static void main(String[] args)
        throws IOException
    {
        new NClient().init();
    }
}
</code></pre>
<p>也可以参考笔记《Java-NIO》的阻塞式、非阻塞式。</p>
<h1 id="使用aio实现非阻塞通信">使用AIO实现非阻塞通信</h1>
<p>AIO（Asynchronous IO），异步IO，是JDK7提供的API。</p>
<h2 id="如何区分io的同步异步和阻塞非阻塞">如何区分IO的同步、异步和阻塞、非阻塞？</h2>
<pre><code class="language-txt">答：IO的操作可以分两步：
1）程序发出IO请求；
2）完成实际的IO操作
如果按第一步来划分：发出IO请求会阻塞线程，则是阻塞IO，如果发出IO请求没有阻塞线程，则是非阻塞式IO。
如果按第二步来划分：实际的IO操作由操作系统来完成，再将结果返回给应用程序，则是异步IO；实际的IO操作由应用程序本身去执行，会阻塞IO，是同步IO。
</code></pre>
<h2 id="示例-3">示例</h2>
<pre><code class="language-txt">使用AsynchronousServerSocketChannel只要三步：
1、调用自身的open()静态方法创建AsynchronousServerSocketChannel。
2、调用AsynchronousServerSocketChannel的bind()方法指定IP地址、端口。
3、调用AsynchronousServerSocketChannel的accept()方法接受连接请求。

使用AsynchronousSocketChannel也只要三步：
1、调用自身的open()静态方法创建AsynchronousSocketChannel。
2、调用AsynchronousSocketChannel的connect()方法连接到指定IP、端口。
调用AsynchronousSocketChannel的read()、write()方法进行读写。
</code></pre>
<p>下面是最简示例：</p>
<p>SimpleAIOServer.java</p>
<pre><code class="language-java">
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.*;

public class SimpleAIOServer
{
    static final int PORT = 30000;
    public static void main(String[] args)
        throws Exception
    {
        try(
            // ①创建AsynchronousServerSocketChannel对象。
            AsynchronousServerSocketChannel serverChannel =
                AsynchronousServerSocketChannel.open())
        {
            // ②指定在指定地址、端口监听。
            serverChannel.bind(new InetSocketAddress(PORT));
            while (true)
            {
                // ③采用循环接受来自客户端的连接
                Future&lt;AsynchronousSocketChannel&gt; future
                    = serverChannel.accept();
                // 获取连接完成后返回的AsynchronousSocketChannel
                AsynchronousSocketChannel socketChannel = future.get();
                // 执行输出。
                socketChannel.write(ByteBuffer.wrap(&quot;欢迎你来自AIO的世界！&quot;
                    .getBytes(&quot;UTF-8&quot;))).get();
            }
        }
    }
}
</code></pre>
<p>SimpleAIOClient.java</p>
<pre><code class="language-java">
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class SimpleAIOClient
{
    static final int PORT = 30000;
    public static void main(String[] args)
        throws Exception
    {
        // 用于读取数据的ByteBuffer。
        ByteBuffer buff = ByteBuffer.allocate(1024);
        Charset utf = Charset.forName(&quot;utf-8&quot;);
        try(
            // ①创建AsynchronousSocketChannel对象
            AsynchronousSocketChannel clientChannel
                = AsynchronousSocketChannel.open())
        {
            // ②连接远程服务器
            clientChannel.connect(new InetSocketAddress(&quot;127.0.0.1&quot;
                , PORT)).get();     // ④
            buff.clear();
            // ③从clientChannel中读取数据
            clientChannel.read(buff).get();     // ⑤
            buff.flip();
            // 将buff中内容转换为字符串
            String content = utf.decode(buff).toString();
            System.out.println(&quot;服务器信息：&quot; + content);
        }
    }
}
</code></pre>
<p>直接创建AsynchronousServerSocketChannel的代码片段如下：</p>
<pre><code class="language-java">AsynchronousServerSocketChannel serverSocketChannel = 
		AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(PORT));
</code></pre>
<p>使用AsynchronousChannelGroup创建AsynchronousServerSocketChannel的代码片段如下：</p>
<pre><code class="language-java">// 创建一个线程池
ExecutorService executor = Executors.newFixedThreadPool(20);
// 以指定线程池来创建一个AsynchronousChannelGroup
AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup
	.withThreadPool(executor);
// 以指定线程池来创建一个AsynchronousServerSocketChannel
AsynchronousServerSocketChannel serverChannel
	= AsynchronousServerSocketChannel.open(channelGroup)
	// 指定监听本机的PORT端口
	.bind(new InetSocketAddress(PORT));
</code></pre>
<pre><code class="language-txt">AsynchronousServerSocketChannel的accept()方法有两个版本，有Future返回值的会阻塞（必须调用get()方法才有返回值），另外一个方法是异步的：

- Future&lt;AsynchronousSocketChannel&gt; accept()，接受客户端请求，如果程序需要获得连接成功后返回的AsynchronousSocketChannel，则应调用该方法返回的Future对象的get()方法——但get()方法会阻塞线程，因此这种方式依然会阻塞当前线程。
- &lt;Object&gt; void accept(Object attachment, CompletionHandler&lt;AsynchronousSocketChannel, ? super Object&gt; handler)，接受客户端请求，连接成功或失败都会触发CompletionHandler对象里相应的方法。其中AsynchronousSocketChannel就代表连接成功后返回的AsynchronousSocketChannel。

CompletionHandler是个接口，该接口定义了两个方法：
- completed(AsynchronousSocketChannel result, Object attachment)，当IO操作成功时触发该方法。第一个参数代表IO操作成功后返回的对象，第二参数代表发起IO操作时传入的附加参数。
- failed(Throwable exc, Object attachment)，当IO操作失败时触发的方法。

AsynchronousSocketChannel的connect()、read()、write()方法都有两个版本，同上。
</code></pre>
<p>完整的示例如下：</p>
<p>AIOServer.java</p>
<pre><code class="language-java">
import java.net.*;
import java.io.*;
import java.util.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.util.concurrent.*;

public class AIOServer
{
    static final int PORT = 30000;
    final static String UTF_8 = &quot;utf-8&quot;;
    static List&lt;AsynchronousSocketChannel&gt; channelList
        = new ArrayList&lt;&gt;();
    public void startListen() throws InterruptedException,
        Exception
    {
        // 创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(20);
        // 以指定线程池来创建一个AsynchronousChannelGroup
        AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup
            .withThreadPool(executor);
        // 以指定线程池来创建一个AsynchronousServerSocketChannel
        AsynchronousServerSocketChannel serverChannel
            = AsynchronousServerSocketChannel.open(channelGroup)
            // 指定监听本机的PORT端口
            .bind(new InetSocketAddress(PORT));
        // 使用CompletionHandler接受来自客户端的连接请求
        serverChannel.accept(null, new AcceptHandler(serverChannel));  // ①
        Thread.sleep(5000);
    }
    public static void main(String[] args)
        throws Exception
    {
        AIOServer server = new AIOServer();
        server.startListen();
    }
    }
    // 实现自己的CompletionHandler类
    class AcceptHandler implements
    CompletionHandler&lt;AsynchronousSocketChannel, Object&gt;
    {
    private AsynchronousServerSocketChannel serverChannel;
    public AcceptHandler(AsynchronousServerSocketChannel sc)
    {
        this.serverChannel = sc;
    }
    // 定义一个ByteBuffer准备读取数据
    ByteBuffer buff = ByteBuffer.allocate(1024);
    // 当实际IO操作完成时候触发该方法
    @Override
    public void completed(final AsynchronousSocketChannel sc
        , Object attachment)
    {
        // 记录新连接的进来的Channel
        AIOServer.channelList.add(sc);
        // 准备接受客户端的下一次连接
        serverChannel.accept(null , this);
        sc.read(buff , null
            , new CompletionHandler&lt;Integer,Object&gt;()  // ②
        {
            @Override
            public void completed(Integer result
                , Object attachment)
            {
                buff.flip();
                // 将buff中内容转换为字符串
                String content = StandardCharsets.UTF_8
                    .decode(buff).toString();
                // 遍历每个Channel，将收到的信息写入各Channel中
                for(AsynchronousSocketChannel c : AIOServer.channelList)
                {
                    try
                    {
                        c.write(ByteBuffer.wrap(content.getBytes(
                            AIOServer.UTF_8))).get();
                    }
                    catch (Exception ex)
                    {
                        ex.printStackTrace();
                    }
                }
                buff.clear();
                // 读取下一次数据
                sc.read(buff , null , this);
            }
            @Override
            public void failed(Throwable ex, Object attachment)
            {
                System.out.println(&quot;读取数据失败: &quot; + ex);
                // 从该Channel读取数据失败，就将该Channel删除
                AIOServer.channelList.remove(sc);
            }
        });
    }
    @Override
    public void failed(Throwable ex, Object attachment)
    {
        System.out.println(&quot;连接失败: &quot; + ex);
    }
}
</code></pre>
<p>AIOClient.java</p>
<pre><code class="language-java">
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.util.concurrent.*;

public class AIOClient
{
    final static String UTF_8 = &quot;utf-8&quot;;
    final static int PORT = 30000;
    // 与服务器端通信的异步Channel
    AsynchronousSocketChannel clientChannel;
    JFrame mainWin = new JFrame(&quot;多人聊天&quot;);
    JTextArea jta = new JTextArea(16 , 48);
    JTextField jtf = new JTextField(40);
    JButton sendBn = new JButton(&quot;发送&quot;);
    public void init()
    {
        mainWin.setLayout(new BorderLayout());
        jta.setEditable(false);
        mainWin.add(new JScrollPane(jta), BorderLayout.CENTER);
        JPanel jp = new JPanel();
        jp.add(jtf);
        jp.add(sendBn);
        // 发送消息的Action,Action是ActionListener的子接口
        Action sendAction = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                String content = jtf.getText();
                if (content.trim().length() &gt; 0)
                {
                    try
                    {
                        // 将content内容写入Channel中
                        clientChannel.write(ByteBuffer.wrap(content
                            .trim().getBytes(UTF_8))).get();    //①
                    }
                    catch (Exception ex)
                    {
                        ex.printStackTrace();
                    }
                }
                // 清空输入框
                jtf.setText(&quot;&quot;);
            }
        };
        sendBn.addActionListener(sendAction);
        // 将Ctrl+Enter键和&quot;send&quot;关联
        jtf.getInputMap().put(KeyStroke.getKeyStroke('\n'
            , java.awt.event.InputEvent.CTRL_MASK) , &quot;send&quot;);
        // 将&quot;send&quot;和sendAction关联
        jtf.getActionMap().put(&quot;send&quot;, sendAction);
        mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainWin.add(jp , BorderLayout.SOUTH);
        mainWin.pack();
        mainWin.setVisible(true);
    }
    public void connect()
        throws Exception
    {
        // 定义一个ByteBuffer准备读取数据
        final ByteBuffer buff = ByteBuffer.allocate(1024);
        // 创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(80);
        // 以指定线程池来创建一个AsynchronousChannelGroup
        AsynchronousChannelGroup channelGroup =
            AsynchronousChannelGroup.withThreadPool(executor);
        // 以channelGroup作为组管理器来创建AsynchronousSocketChannel
        clientChannel = AsynchronousSocketChannel.open(channelGroup);
        // 让AsynchronousSocketChannel连接到指定IP、指定端口
        clientChannel.connect(new InetSocketAddress(&quot;127.0.0.1&quot;
            , PORT)).get();
        jta.append(&quot;---与服务器连接成功---\n&quot;);
        buff.clear();
        clientChannel.read(buff, null
            , new CompletionHandler&lt;Integer,Object&gt;()   //②
        {
            @Override
            public void completed(Integer result, Object attachment)
            {
                buff.flip();
                // 将buff中内容转换为字符串
                String content = StandardCharsets.UTF_8
                    .decode(buff).toString();
                // 显示从服务器端读取的数据
                jta.append(&quot;某人说：&quot; + content + &quot;\n&quot;);
                buff.clear();
                clientChannel.read(buff , null , this);
            }
            @Override
            public void failed(Throwable ex, Object attachment)
            {
                System.out.println(&quot;读取数据失败: &quot; + ex);
            }
        });
    }
    public static void main(String[] args)
        throws Exception
    {
        AIOClient client = new AIOClient();
        client.init();
        client.connect();
    }
}
</code></pre>
<h1 id="udp">UDP</h1>
<p>udp是一种不可靠的网络协议，只负责发送或接收（不管对方的状态）。</p>
<p>udp没有服务端、客户端之分，都用DatagramSocket表示，不维护状态、不产生IO流，只负责接收和发送数据报。而数据报用DatagramPacket表示。</p>
<p>虽然没有服务端、客户端之分，但通常固定IP、固定端口的DatagramSocket对象所在的程序称为服务器，可以用它来接收客户端的数据。</p>
<h2 id="原理示例">原理示例</h2>
<p><img src="https://oscimg.oschina.net/oscnet/07922bfb36f8dbcd98cf58aa9cd1f3adf77.jpg" alt="udp-example" title="udp-example"></p>
<pre><code class="language-java">class UDPServer{
    public static void main(String[] args)throws IOException{
        DatagramSocket  server = new DatagramSocket(5050);
        byte[] recvBuf = new byte[100];
        DatagramPacket recvPacket 
            = new DatagramPacket(recvBuf , recvBuf.length);
        server.receive(recvPacket);
        String recvStr = new String(recvPacket.getData() , 0 , recvPacket.getLength());
        System.out.println(&quot;Hello World!&quot; + recvStr);
        int port = recvPacket.getPort();
        InetAddress addr = recvPacket.getAddress();
        String sendStr = &quot;Hello ! I'm Server&quot;;
        byte[] sendBuf;
        sendBuf = sendStr.getBytes();
        DatagramPacket sendPacket 
            = new DatagramPacket(sendBuf , sendBuf.length , addr , port );
        server.send(sendPacket);
        server.close();
    }
}
class UDPClient{
    public static void main(String[] args)throws IOException{
        DatagramSocket client = new DatagramSocket();
        
        String sendStr = &quot;Hello! I'm Client&quot;;
        byte[] sendBuf;
        sendBuf = sendStr.getBytes();
        InetAddress addr = InetAddress.getByName(&quot;127.0.0.1&quot;);
        int port = 5050;
        DatagramPacket sendPacket 
            = new DatagramPacket(sendBuf ,sendBuf.length , addr , port);
        client.send(sendPacket);
        byte[] recvBuf = new byte[100];
        DatagramPacket recvPacket
            = new DatagramPacket(recvBuf , recvBuf.length);
        client.receive(recvPacket);
        String recvStr = new String(recvPacket.getData() , 0 ,recvPacket.getLength());
        System.out.println(&quot;收到:&quot; + recvStr);
        client.close();
    }
}
</code></pre>
<p>from <a href="http://blog.csdn.net/wintys/article/details/3525643/">http://blog.csdn.net/wintys/article/details/3525643/</a></p>
<h2 id="multicastsocket">MulticastSocket</h2>
<p>DatagramSocket只允许数据发送给指定的目标地址，而MulticastSocket可以将数据报以广播方式发送到多个客户端。</p>
<h1 id="tcpudp比较">TCP/UDP比较</h1>
<p>tcp协议：可靠，传输大小无限制，但是需要建立连接，差错控制开销大。</p>
<p>udp协议：不可靠，传输大小限制在64KB以下，不需要建立连接，差错控制开销小。</p>
<h1 id="q--a">Q &amp; A</h1>
<h2 id="tcp与http协议的区别">TCP与Http协议的区别</h2>
<p><img src="https://oscimg.oschina.net/oscnet/5858a792ec3ba4e2077737a712de9f12877.jpg" alt="image"></p>

    </div>
    <div class="article-footer">
<blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    <li class="post-copyright-link hidden-xs">
      <strong>Permalink: </strong>
      <a href="https://rulerLwx.gitee.io/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-1/" title="Java-Se-网络编程-1" target="_blank" rel="external">https://rulerLwx.gitee.io/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-1/</a>
    </li>
    <li class="post-copyright-license">
      <strong>License：</strong><a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN</a>
    </li>
  </ul>
</blockquote>

<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://gitee.com/rulerLwx" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="https://rulerLwx.gitee.io/avatar.png" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://gitee.com/rulerLwx" target="_blank"><span class="text-dark">rulerLwx</span><small class="ml-1x">thinking...</small></a></h3>
        <div>Good Good Study, Day Day Up~</div>
      </div>
    </figure>
  </div>
</div>
    </div>
  </article>
<section id="comments">
    <div id="vcomments"></div>
</section>

</div><nav class="bar bar-footer clearfix" data-stick-bottom>
    <div class="bar-inner">
        <ul class="pager pull-left">
            <li class="prev">
                <a href="https://rulerLwx.gitee.io/2017/07/java-se-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/" title="Java-Se-面向对象"><i
                        class="icon icon-angle-left"
                        aria-hidden="true"></i><span>&nbsp;&nbsp;Older</span></a>
            </li>
            <li class="next">
                <a href="https://rulerLwx.gitee.io/2017/07/java-se-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-2-%E6%8F%A1%E6%89%8B/"
                    title="Java-Se-网络编程-2"><span>Newer&nbsp;&nbsp;</span><i
                        class="icon icon-angle-right" aria-hidden="true"></i></a>
            </li>
            
            <li class="toggle-toc">
                <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false"
                    title="Catalogue" role="button">
                    <span>[&nbsp;</span><span>Catalogue</span>
                    <i class="text-collapsed icon icon-anchor"></i>
                    <i class="text-in icon icon-close"></i>
                    <span>]</span>
                </a>
            </li>
        </ul>
        <div class="bar-right">
            <div class="share-component" data-sites="weibo,qq,wechat"
                data-mobile-sites="weibo,qq,qzone"></div>
        </div>
    </div>
</nav>

</main><footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
<ul class="social-links">
    <li><a href="https://gitee.com/rulerLwx" target="_blank" title="gitee" data-toggle=tooltip data-placement=top >
            <i class="icon icon-gitee"></i></a></li>
    <li><a href="https://github.com/wolf-lea" target="_blank" title="github" data-toggle=tooltip data-placement=top >
            <i class="icon icon-github"></i></a></li>
</ul>
  <div class="copyright">
    &copy;2017  -
    2020
    <div class="publishby">
        Theme by <a href="https://github.com/xiaoheiAh" target="_blank"> xiaoheiAh </a>base on<a href="https://github.com/xiaoheiAh/hugo-theme-pure" target="_blank"> pure</a>.
    </div>
  </div>
</footer>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_SVG"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
            showMathMenu: false, //disables context menu
            tex2jax: {
            inlineMath: [ ['$','$'], ['\\(','\\)'] ]
           }
    });
</script>


<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script>
    window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/highlight.min.js"></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/python.min.js" defer></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/javascript.min.js" defer></script><script>
    hljs.configure({
        tabReplace: '    ', 
        classPrefix: ''     
        
    })
    hljs.initHighlightingOnLoad();
</script>
<script src="https://rulerLwx.gitee.io/js/application.min.bdeb64b910570b6c41badc6a05b7afb0c8ad9efd8525de3c7257d59e786326a3.js"></script>
<script src="https://rulerLwx.gitee.io/js/plugin.min.51ff8c7317566f82259170fa36e09c4493adc9b9378b427a01ad3f017ebac7dd.js"></script>

<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: 'Posts',
                PAGES: 'Pages',
                CATEGORIES: 'Categories',
                TAGS: 'Tags',
                UNTITLED: '(Untitled)',
            },
            ROOT_URL: 'https:\/\/rulerLwx.gitee.io',
            CONTENT_URL: 'https:\/\/rulerLwx.gitee.io\/searchindex.json ',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script type="text/javascript" src="https://rulerLwx.gitee.io/js/insight.min.a343cd9a5a7698336b28ef3a7c16a3a1b1d2d5fb17dc8ed04022bbe08cc5459073a15bdafa3a8a58cdd56080784bdd69fa70b1ae8597565c799c57ed00f0e120.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script>
<script>
    tocbot.init({
        
        tocSelector: '.js-toc',
        
        contentSelector: '.js-toc-content',
        
        headingSelector: 'h1, h2, h3',
        
        hasInnerContainers: true,
    });
</script>

<script src="https://cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine"></script>
<script type="text/javascript">
    var GUEST = ['nick', 'mail', 'link'];
    var meta = 'nick,mail';
    meta = meta.split(',').filter(function (item) {
        return GUEST.indexOf(item) > -1;
    });
    new Valine({
        el: '#vcomments',
        verify: null ,
        notify: null ,
        appId: 'IyAB0PSPRazTPDxitO1ddQ7O-gzGzoHsz',
        appKey: '5rBJTq4KidYF33eXwvRVhtEH',
        placeholder: 'enjoy~',
        avatar: 'mm',
        meta: meta,
        pageSize: '10' || 10,
        visitor: false 
});
</script>

  </body>
</html>
